package com.jihox.abookpro.util;

import java.util.*;
import java.io.File;

public class MyMap  extends Hashtable{
	
	public static final long serialVersionUID = 1;
	private List theseKeys=new Vector();

	public MyMap()
	{
	}

	public MyMap(Map other)
	{
		super(other);
	}
	
	public List getTheseKeys() 
	{ 
		return theseKeys; 
	}
	
	private void addTheseKeys(Object key) 
	{
		if (theseKeys.contains(key))
		{
			theseKeys.remove(key);
		}
		theseKeys.add(key);
	}
	
	private boolean removeTheseKeys(Object key) 
	{
		return theseKeys.remove(key);
	}

	private Object actual_get(Object key, Object def)
	{
		Object result = super.get(key);
		return (result == null) ? (def) : (result);

	}

	public Object get(Object key, Object def)
	{
		return actual_get(key, def);
	}

	public Object getRequired(Object key) throws Exception
	{
		Object result = get(key);
		if (null != result)
			return result;

		throw new Exception("Missing: " + key);
	}

	public Number getRequiredNumber(Object key) throws Exception
	{
		Number result = getNumber(key);
		if (null != result)
			return result;

		throw new Exception("Missing: " + key);
	}

	public String getRequiredString(Object key) throws Exception
	{
		String result = getString(key);
		if (null != result)
			return result;

		throw new Exception("Missing: " + key);
	}

	public File getRequiredFile(Object key) throws Exception
	{
		File result = getFile(key);
		if (null != result)
			return result;

		throw new Exception("Missing: " + key);
	}

	public Boolean getRequiredBoolean(Object key) throws Exception
	{
		Boolean result = getBoolean(key);
		if (null != result)
			return result;

		throw new Exception("Missing: " + key);
	}

	public Integer get(Object key, Integer def)
	{
		return (Integer) actual_get(key, def);
	}

	public String get(Object key, String def)
	{
		return (String) actual_get(key, def);
	}
	
	public Boolean get(Object key, Boolean def)
	{
		// the DB will use integer as boolean, so make sure it works either way
		Object obj = actual_get(key, def);
		if (obj instanceof Integer)
			return (((Integer) obj).intValue() == 0) ? (Boolean.FALSE) : (Boolean.TRUE);
		else
			return (Boolean) obj;
	}

	public Integer get(Object key, int def)
	{
		return (Integer) actual_get(key, new Integer(def));
	}

	public final Object put(Object key, long value)
	{
		return put(key, new Long(value));
	}

	public final Object put(Object key, int value)
	{
		return put(key, new Integer(value));
	}

	public final Object put(Object key, boolean value)
	{
		return put(key, new Boolean(value));
	}

	public final Object put(Object key, char value)
	{
		return put(key, new Character(value));
	}

	public final Object put(Object key, double value)
	{
		return put(key, new Double(value));
	}

	public final Object put(Object key, float value)
	{
		return put(key, new Float(value));
	}

	public final Object put(Object key, byte value)
	{
		return put(key, new Byte(value));
	}

	public final Object put(Object key, short value)
	{
		return put(key, new Short(value));
	}
	
	public final Object putList(Object key, Collection value)
	{
		Map map = new MyMap ();
		Iterator iter = value.iterator();
		int index = 0;
		while (iter.hasNext())
		{
			map.put("item" + (index++) , iter.next());
		}
		return this.put(key, map);
	}
	
	public final Object put(Object key, Object value)
	{
		if ((key != null) && (value != null)) 
		{
			addTheseKeys(key);
			return super.put(key, value);
		}
		super.remove(key);
		removeTheseKeys(key);
		return null;
	}

	public Boolean getBoolean(Object key)
	{
		return getBoolean(key, null);
	}

	public Boolean getBoolean(Object key, Boolean def)
	{
		try
		{
			Object result = actual_get(key, def);
			if (result != null && !(result instanceof Boolean))
			{
				result = new Boolean(((Integer) result).intValue() == 0) ? (Boolean.FALSE) : (Boolean.TRUE);
			}
			return (Boolean)result;
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public File getFile(Object key)
	{
		return getFile(key, null);
	}

	public File getFile(Object key, File def)
	{
		try
		{
			return (File) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Vector getVector(Object key)
	{
		return getVector(key, null);
	}

	public Vector getVector(Object key, Vector def)
	{
		try
		{
			return (Vector) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Map getMap(Object key)
	{
		return getMap(key, null);
	}

	public Map getMap(Object key, Map def)
	{
		try
		{
			return (Map) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public byte[] getByteArray(Object key)
	{
		return getByteArray(key, null);
	}

	public byte[] getByteArray(Object key, byte[] def)
	{
		try
		{
			return (byte[]) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Number getNumber(Object key)
	{
		return getNumber(key, null);
	}

	public Number getNumber(Object key, Number def)
	{
		try
		{
			return (Number) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Integer getInteger(Object key)
	{
		return getInteger(key, null);
	}

	public Integer getInteger(Object key, Integer def)
	{
		try
		{
			Object result = actual_get(key, def);
			if (result != null && !(result instanceof Integer))
			{
				result = new Integer (((Number) result).intValue());
			}
			return (Integer) result;
		}
		catch (ClassCastException e)
		{
			return def;
		}
	}

	public Double getDouble(Object key)
	{
		return getDouble(key, null);
	}

	public Double getDouble(Object key, Double def)
	{
		try
		{
			return (Double) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Float getFloat(Object key)
	{
		return getFloat(key, null);
	}

	public Float getFloat(Object key, Float def)
	{
		try
		{
			//sometimes float & double are mixed, so be nice and allow them	
			Object result = actual_get(key, def);
			if (result instanceof Double)
			{
				result = new Float (((Double) result).doubleValue());
			}
			return (Float) result;
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public String getString(Object key)
	{
		return getString(key, null);
	}

	public String getString(Object key, String def)
	{
		try
		{
			return (String) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public Date getDate(Object key)
	{
		return getDate(key, null);
	}

	public Date getDate(Object key, Date def)
	{
		try
		{
			return (Date) actual_get(key, def);
		}
		catch (ClassCastException e)
		{
			return null;
		}
	}

	public final Collection getList(Object key)
	{
		Vector result = new Vector ();
		try
		{
			Map map = (Map) actual_get(key, new MyMap ());
			Collection col = map.values();
			Iterator iter = col.iterator();
			while (iter.hasNext())
			{
				result.add(iter.next());
			}
			return result;
		}
		catch (ClassCastException e)
		{
		}
		return result;
	}
}
